#include	"logger.h"

#include	<cstdarg>
#include	<cstdio>
#include	<cstring>
#include	<ctime>

#if defined(_WIN32)
#	include	<Windows.h>
#	pragma	warning(disable:4996)
#endif

using namespace std;

#define LOG_BUF_SIZE	1048576

static void MAKE_LOG(char * pBuf, size_t nSize, const char nType, const char * pFmt, va_list args) {
	int nOffset = 0;
	memset(pBuf, 0, nSize);

#if defined(_WIN32)
	SYSTEMTIME iTime;
	GetLocalTime(&iTime);

	nOffset = snprintf(pBuf, nSize, "[%04d-%02d-%02d %02d:%02d:%02d.%03d][%c]",
		iTime.wYear, iTime.wMonth, iTime.wDay, iTime.wHour, iTime.wMinute, iTime.wSecond, iTime.wMilliseconds, nType);
#else
	struct tm iTime;
	struct timespec iDetail;

	clock_gettime(CLOCK_REALTIME, &iDetail);
	localtime_r(&iDetail.tv_sec, &iTime);

	nOffset = snprintf(pBuf, nSize, "[%04d-%02d-%02d %02d:%02d:%02d.%03d][I]",
		iTime.tm_year + 1900, iTime.tm_mon + 1, iTime.tm_mday, iTime.tm_hour, iTime.tm_min, iTime.tm_sec, (int)(iDetail.tv_nsec / 1000000));
#endif

	vsnprintf(pBuf + nOffset, nSize - nOffset, pFmt, args);
}

Logger::Logger() : _pBuf(new char[LOG_BUF_SIZE]), _iLock() {
}

Logger::~Logger() {
	if (_pBuf) delete _pBuf;
}

Logger & Logger::Get() {
	static Logger * pIns = nullptr;
	if (pIns == nullptr) pIns = new Logger;
	return *pIns;
}

void Logger::Error(const char * pFmt, ...) {
	unique_lock<mutex> _(_iLock);	

	va_list args;
	va_start(args, pFmt);
	MAKE_LOG(_pBuf, LOG_BUF_SIZE, 'E', pFmt, args);
	va_end(args);

	printf("%s\n", _pBuf);
}

void Logger::Warn(const char * pFmt, ...) {
	unique_lock<mutex> _(_iLock);

	va_list args;
	va_start(args, pFmt);
	MAKE_LOG(_pBuf, LOG_BUF_SIZE, 'W', pFmt, args);
	va_end(args);

	printf("%s\n", _pBuf);
}

void Logger::Info(const char * pFmt, ...) {
	unique_lock<mutex> _(_iLock);

	va_list args;
	va_start(args, pFmt);
	MAKE_LOG(_pBuf, LOG_BUF_SIZE, 'I', pFmt, args);
	va_end(args);

	printf("%s\n", _pBuf);
}

void Logger::Debug(const char * pFmt, ...) {
	unique_lock<mutex> _(_iLock);

	va_list args;
	va_start(args, pFmt);
	MAKE_LOG(_pBuf, LOG_BUF_SIZE, 'D', pFmt, args);
	va_end(args);

	printf("%s\n", _pBuf);
}
